import copy
import math

import numpy as np

from coin.proto.coin_request_pb2 import AccountRequestProto


def pretty_time_delta(seconds):
  sign_string = '-' if seconds < 0 else ''
  seconds = abs(int(seconds))
  days, seconds = divmod(seconds, 86400)
  hours, seconds = divmod(seconds, 3600)
  minutes, seconds = divmod(seconds, 60)
  if days > 0:
    return '%s%02d:%02d:%02d' % (sign_string, days * 24 + hours, minutes, seconds)
  elif hours > 0:
    return '%s%02d:%02d:%02d' % (sign_string, hours, minutes, seconds)
  elif minutes > 0:
    return '%s00:%02d:%02d' % (sign_string, minutes, seconds)
  else:
    return '%s00:00:%02d' % (sign_string, seconds)


_currency_format_map = {
    # coin
    # more than 50 USD
    "BCH": "{:.2f}",
    "BTC": "{:.4f}",
    "DASH": "{:.2f}",
    "EOS": "{:.2f}",
    "ETC": "{:.2f}",
    "ETH": "{:.2f}",
    "LTC": "{:.2f}",
    "NEO": "{:.2f}",
    "XMR": "{:.2f}",
    "ZCASH": "{:.2f}",  # fiat or quote
    "EUR": "{:,.2f}",
    "KRW": "{:,.0f}",
    "JPY": "{:,.0f}",
    "USD": "{:,.2f}",
    "USDT": "{:,.2f}",
}


def guess_format_currency(symbol):
  if symbol.endswith("_IN_BTC"):
    currency = "BTC"
  elif symbol.endswith("_IN_KRW"):
    currency = "KRW"
  elif symbol.endswith("_IN_USD"):
    currency = "USD"
  elif symbol.endswith("_IN_USDT"):
    currency = "USDT"
  elif symbol.endswith("_value_BTC"):
    currency = "BTC"
  elif symbol.endswith("_value_KRW"):
    currency = "KRW"
  elif symbol.endswith("_value_USD"):
    currency = "USD"
  elif symbol.endswith("_value_USDT"):
    currency = "USDT"
  elif symbol.endswith("-KRW"):
    currency = symbol[:-4]
  else:
    currency = symbol
  return currency


def gen_format_currency_functor(currency, print_zero=False):
  currency = guess_format_currency(currency)
  if currency in _currency_format_map:
    fmt = _currency_format_map[currency]
  else:
    fmt = "{:.0f}"

  def f(num):
    if isinstance(num, float):
      if not math.isnan(num):
        if print_zero or abs(num) >= 1e-4:
          return fmt.format(num)
        else:
          return ""
      else:
        return ""
    else:
      return num

  return f


def format_currency_value(currency, value, print_zero=False):
  f = gen_format_currency_functor(currency, print_zero)
  return f(value)


def format_currency_df(df, print_zero=False):
  for col in df.columns:
    f = gen_format_currency_functor(col, print_zero=print_zero)
    df[col] = df[col].map(f)
  return df


def gen_accounting_cols(accounting_currency):
  return [
      "quote_value_" + accounting_currency,
      "coin_value_" + accounting_currency,  # base_currency all converted
      "total_value_" + accounting_currency
  ]


def move_columns_to_front(all_columns, cols):
  for col in reversed(cols):
    if col in all_columns:
      all_columns.remove(col)
      all_columns = [col] + all_columns
  return all_columns


def move_columns_to_back(all_columns, cols):
  for col in cols:
    if col in all_columns:
      all_columns.remove(col)
      all_columns = all_columns + [col]
  return all_columns


def set_df_nan(df, cols):
  for col in cols:
    if col not in df.columns:
      df[col] = np.nan
  return df


def move_df_nan_back(df, cols):
  df = set_df_nan(df, cols)
  df = df[move_columns_to_back(df.columns.tolist(), cols)]
  return df


def move_request_to_front(df):
  fields = [elem.name for elem in AccountRequestProto.DESCRIPTOR.fields]
  df = df[move_columns_to_front(df.columns.tolist(), fields)]
  return df


def move_accounting_currency_to_last(df, accounting_currency):
  df = df[move_columns_to_back(df.columns.tolist(), gen_accounting_cols(accounting_currency))]
  return df


def format_value(df):
  df = format_currency_df(df)
  df = move_request_to_front(df)
  return df.fillna("")


def print_format_accounting_currency(df):
  df = copy.copy(df)
  df = format_value(df)
  print(df)


def print_total_impl(df_to_string):
  print("\n==================================\n")
  print("Total:\n")
  total_string = df_to_string.split('\n')
  prev = 2
  curr = 0
  fields = [elem.name for elem in AccountRequestProto.DESCRIPTOR.fields]
  for line in total_string:
    if line.strip() in fields:
      continue
    curr = len(line.split())
    if curr == 3 and prev == 2:
      print("-----------------")
      print(line)
      prev = 3
    else:
      print(line)


def print_total(df):
  df = copy.copy(df)
  df = format_value(df)
  print_total_impl(df.loc['Total'].to_string())
